/**
 * 问题:
 * 实现一个flatten方法, 将对象扁平化
 * 
 * 描述:
 * const obj = { 
 *   a: { b: 1, c: 2, d: {e: 5} }, 
 *   b: [1, 3, {a: 2, b: 3}], 
 *   c: 3 
 * }
 * 
 * flatten(obj) 结果返回如下
 * { 
 *   'a.b': 1, 
 *   'a.c': 2, 
 *   'a.d.e': 5, 
 *   'b[0]': 1, 
 *   'b[1]': 3, 
 *   'b[2].a': 2, 
 *   'b[2].b': 3, 
 *   c: 3 
 * }
*/

const obj = {
  a: {
         b: 1,
         c: 2,
         d: {e: 5}
     },
  b: [1, 3, {a: 2, b: 3}],
  c: 3
 }

/**
 * 方式1
 * @param {Object} obj 传入的对象
 * @param {String} path 默认空字符, 每次递归传入的key
 * @returns {Object} 扁平后的对象
 */

function flatten1(obj, path='') {
  if (!(obj instanceof Object)) {
    return { [path.replace(/\.$/g, '')]: obj }
  }
  
  return Object.keys(obj).reduce((output, key) => {
    return (obj instanceof Array) ?
      { ...output, ...flatten1(obj[key], path + '[' + key + '].') } :
      {...output, ...flatten1(obj[key], path + key + '.') }
  }, {})
}

const res = flatten1(obj)
console.log(res)
// {
//   'a.b': 1,
//   'a.c': 2,
//   'a.d.e': 5,
//   'b.[0]': 1,
//   'b.[1]': 3,
//   'b.[2].a': 2,
//   'b.[2].b': 3,
//   c: 3
// }






/**
 * 方式2
 * @param {Object} obj 传入的对象
 * @returns {Object} 扁平后的对象
 */

// 是否是一个对象
const isObject = (val) =>  typeof val === "object" && val !== null

function flatten2(obj) {
  const res = {}

  const dfs = (curr, prefix='') => {
    if (!isObject(curr)) {
      res[prefix] = curr
      return
    }
    if (Array.isArray(curr)) {
      curr.forEach((item,index) => {
        dfs(item, prefix + `[${index}]`)
      })
    } else {
      for (let key in curr) {
        dfs(curr[key], prefix ? `${prefix}.${key}` : key)
      }
    }
  }
  dfs(obj)

  return res
}

const res2 = flatten2(obj)
console.log(res2)
// {
//   'a.b': 1,
//   'a.c': 2,
//   'a.d.e': 5,
//   'b[0]': 1,
//   'b[1]': 3,
//   'b[2].a': 2,
//   'b[2].b': 3,
//   c: 3
// }
